//
//  UIView+WZLBadge.m
//  WZLBadgeDemo
//
//  Created by zilin_weng on 15/6/24.
//  Copyright (c) 2015年 Weng-Zilin. All rights reserved.
//

#import "UIView+WZLBadge.h"
#import <objc/runtime.h>
#import "CAAnimation+WAnimation.h"

@implementation UIView (WZLBadge)

#pragma mark -- public methods
/**
 *  show badge with red dot style and WBadgeAnimTypeNone by default.
 */
- (void)showBadge
{
    [self showBadgeWithStyle:WBadgeStyleRedDot value:0 animationType:WBadgeAnimTypeNone];
}

/**
 *  showBadge
 *
 *  @param style WBadgeStyle type
 *  @param value (if 'style' is WBadgeStyleRedDot or WBadgeStyleNew,
 *                this value will be ignored. In this case, any value will be ok.)
 */
- (void)showBadgeWithStyle:(WBadgeStyle)style value:(NSInteger)value animationType:(WBadgeAnimType)aniType
{
    self.aniType = aniType;
    switch (style) {
        case WBadgeStyleRedDot:
            [self showRedDotBadge];
            break;
        case WBadgeStyleNumber:
            [self showNumberBadgeWithValue:value];
            break;
        case WBadgeStyleNew:
            [self showNewBadge];
            break;
        case WBadgeStyleRectangle:
            [self showRectangleBadgeWithValue:[@(value)stringValue]];
            break;
        default:
            break;
    }
    if (aniType != WBadgeAnimTypeNone) {
        [self beginAnimation];
    }
}

/**
 *  clear badge
 */
- (void)clearBadge
{
    UIView *bgView = (UIView *)[self viewWithTag:(WBadgeStyleRectangle+111)];
    bgView.hidden = YES;
    [bgView removeFromSuperview];
    self.badge.hidden = YES;
}

#pragma mark -- private methods
- (void)showRedDotBadge
{
    [self badgeInit];
    //if badge has been displayed and, in addition, is was not red dot style, we must update UI.
    if (self.badge.tag != WBadgeStyleRedDot) {

        CGRect frame = self.badge.frame;
        frame.size = CGSizeMake(6, 6);
        self.badge.frame = frame;
        self.badge.text = @"";
        self.badge.tag = WBadgeStyleRedDot;
        self.badge.layer.cornerRadius = CGRectGetWidth(self.badge.frame) / 2;
    }
    self.badge.center = CGPointMake(CGRectGetWidth(self.frame) + self.badgeCenterOffset.x, self.badgeCenterOffset.y);
    self.badge.hidden = NO;
//    self.badge.layer.borderColor = [UIColor whiteColor].CGColor;
//    self.badge.layer.borderWidth = 0.75f;
    [self setBadgePropertyWithShadowOpacity:0.4 shadowOffset:CGSizeMake(0,2)];
}

- (void)showNewBadge
{
    [self badgeInit];

    if (self.badge.tag != WBadgeStyleNew) {
        self.badge.text = @"新";
        self.badge.tag = WBadgeStyleNew;

        CGRect frame = self.badge.frame;
        frame.size.width = 13;
        frame.size.height = 13;
        self.badge.frame = frame;

        self.badge.center = CGPointMake(CGRectGetWidth(self.frame) + 2 + self.badgeCenterOffset.x, self.badgeCenterOffset.y);
        self.badge.font = [UIFont boldSystemFontOfSize:9];
        self.badge.layer.cornerRadius = CGRectGetHeight(self.badge.frame) / 2;
        self.badge.layer.borderColor = [UIColor whiteColor].CGColor;
        self.badge.layer.borderWidth = 0.75f;
    }
    self.badge.hidden = NO;
}

- (void)showNumberBadgeWithValue:(NSInteger)value
{
    if (value < 0) {
        return;
    }
    [self badgeInit];
    self.badge.hidden = (value == 0);
    self.badge.tag = WBadgeStyleNumber;
    self.badge.font = [UIFont systemFontOfSize:10];
    self.badgeBgColor = [UIColor colorWithRed:247/255.0 green:67/255.0 blue:39/255.0 alpha:1];
    self.badge.text = (value > kWZLBadgeMaximumBadgeNumber) ? @"..." :
                       [NSString stringWithFormat:@"%@", @(value)];
    [self adjustLabelWidth:self.badge];
    CGRect frame = self.badge.frame;
    frame.size.width = frame.size.width+6;
    frame.size.height = 14;
    if (value > kWZLBadgeMaximumBadgeNumber) {
        frame.size.width = 14;
    }
//    self.badge.layer.borderColor = [UIColor whiteColor].CGColor;
//    self.badge.layer.borderWidth = 0.75f;

    if(CGRectGetWidth(frame) < CGRectGetHeight(frame)) {
        frame.size.width = CGRectGetHeight(frame);
    }
    self.badge.frame = frame;
    self.badge.center = CGPointMake(CGRectGetWidth(self.frame) + self.badgeCenterOffset.x, self.badgeCenterOffset.y);
    
    self.badge.layer.cornerRadius = CGRectGetHeight(self.badge.frame) *.5f;
    [self setBadgePropertyWithShadowOpacity:0.4 shadowOffset:CGSizeMake(0,2)];
}

- (void)showRectangleBadgeWithValue:(NSString *)value {
    [self showRectangleBadgeWithCorner:UIRectCornerAllCorners value:value];
}

- (void)showRectangleBadgeWithCorner:(UIRectCorner)style value:(NSString *)value {
//    [self badgeInit];
    UIView *bgView = [[UIView alloc]init];
    bgView.tag = WBadgeStyleRectangle+111;
    bgView.layer.shadowOpacity = 0.4f;
    bgView.layer.shadowColor = [UIColor colorWithRed:245/255.0 green:67/255.0 blue:39/255.0 alpha:1].CGColor;
    bgView.layer.shadowOffset = CGSizeMake(0,2);
    [self badgeInit];
    self.badge.tag = WBadgeStyleRectangle;
    self.badge.textAlignment = NSTextAlignmentCenter;
    self.badge.textColor = [UIColor whiteColor];
    self.badge.font = [UIFont systemFontOfSize:9];
    bgView.hidden = value?NO:YES;
    self.badge.hidden = value?NO:YES;
    self.badge.text = value;
    [self.badge sizeToFit];
    CGRect frame = self.badge.frame;
    frame.size.width = frame.size.width + 6;
    frame.size.height = 14;
    self.badge.frame = CGRectMake(0, 0, frame.size.width, frame.size.height);
    bgView.frame = frame;
    bgView.center = CGPointMake(CGRectGetWidth(self.frame) + self.badgeCenterOffset.x, self.badgeCenterOffset.y);
    CAShapeLayer *layer = [CAShapeLayer layer];
    layer.fillColor = [UIColor colorWithRed:245/255.0 green:67/255.0 blue:39/255.0 alpha:1].CGColor;
    struct CornerRadii c ;
    c.bottomRight=c.topRight =c.topLeft=c.bottomLeft = 1;
    if (style & UIRectCornerTopLeft) {
        c.topLeft = bgView.bounds.size.height/2+1;
    }
    if (style & UIRectCornerTopRight) {
        c.topRight = bgView.bounds.size.height/2+1;;
    }
    if (style & UIRectCornerBottomLeft) {
        c.bottomLeft = bgView.bounds.size.height/2+1;;
    }
    if (style & UIRectCornerBottomRight) {
        c.bottomRight = bgView.bounds.size.height/2+1;;
    }
    layer.path = [self createPathWithRoundedRect:bgView.bounds cornerRadii:c].CGPath;
    layer.frame = bgView.bounds;
    [bgView.layer addSublayer:layer];
    if (self.badge.superview != self) {
        [self addSubview:self.badge];
    }
    [self insertSubview:bgView belowSubview:self.badge];
    self.badgeBgColor = [UIColor clearColor];
    self.badge.layer.backgroundColor = [UIColor clearColor].CGColor;
}

- (BOOL)isIPhone5
{
    return (int)[[ UIScreen mainScreen] bounds].size.height == 568;
}
- (BOOL)isIPhone6
{
    if ([[[UIDevice currentDevice] name] isEqualToString:@"iPhone Simulator"]) {
        return [UIScreen mainScreen].bounds.size.width == 375;
    }
    return ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? (CGSizeEqualToSize(CGSizeMake(750, 1334), [[UIScreen mainScreen] currentMode].size) || CGSizeEqualToSize(CGSizeMake(640, 1136), [[UIScreen mainScreen] currentMode].size)) : NO);
}

- (BOOL)isIPhone6Plus
{
    if ([[[UIDevice currentDevice] name] isEqualToString:@"iPhone Simulator"]) {
        return [UIScreen mainScreen].bounds.size.width == 414;
    }
    return ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? (CGSizeEqualToSize(CGSizeMake(1125, 2001), [[UIScreen mainScreen] currentMode].size) || CGSizeEqualToSize(CGSizeMake(1242, 2208), [[UIScreen mainScreen] currentMode].size)) : NO);
}


//lazy loading
- (void)badgeInit
{
    if (self.badgeBgColor == nil) {
        self.badgeBgColor = [UIColor colorWithRed:245/255.0 green:67/255.0 blue:39/255.0 alpha:1];
    }
    if (self.badgeTextColor == nil) {
        self.badgeTextColor = [UIColor whiteColor];
    }

    if (nil == self.badge) {
        CGFloat redotWidth = 6;
        CGRect frm = CGRectMake(CGRectGetWidth(self.frame), -redotWidth, redotWidth, redotWidth);
        self.badge = [[BadgeLabel alloc] initWithFrame:frm];
        self.badge.textAlignment = NSTextAlignmentCenter;
        self.badge.center = CGPointMake(CGRectGetWidth(self.frame) + 2 + self.badgeCenterOffset.x, self.badgeCenterOffset.y);
        self.badge.backgroundColor = self.badgeBgColor;
        self.badge.textColor = self.badgeTextColor;
        self.badge.text = @"";
        self.badge.tag = WBadgeStyleRedDot;//red dot by default
        self.badge.layer.cornerRadius = CGRectGetWidth(self.badge.frame) / 2;
        self.badge.layer.masksToBounds = YES;//very important
        self.badge.hidden = NO;
        [self addSubview:self.badge];
    }
}

- (void)setBadgePropertyWithShadowOpacity:(CGFloat)so shadowOffset:(CGSize)soff {
    self.badge.layer.masksToBounds = NO;
    self.badge.backgroundColor = [UIColor clearColor];
    self.badge.layer.backgroundColor = [UIColor colorWithRed:245/255.0 green:67/255.0 blue:39/255.0 alpha:1].CGColor;
    self.badge.layer.shadowOpacity = so;
    self.badge.layer.shadowRadius = 2;
    self.badge.layer.shadowColor = [UIColor colorWithRed:245/255.0 green:67/255.0 blue:39/255.0 alpha:1].CGColor;
    self.badge.layer.shadowOffset = soff;
}

#pragma mark --  other private methods
- (void)adjustLabelWidth:(UILabel *)label
{
    [label setNumberOfLines:0];
    NSString *s = label.text;
    UIFont *font = [label font];
    CGSize size = CGSizeMake(320,2000);

    NSDictionary *attributes = @{NSFontAttributeName: font};
    CGRect rectString = [s boundingRectWithSize:size
                                           options:NSStringDrawingUsesLineFragmentOrigin
                                        attributes:attributes
                                           context:nil];
    CGSize labelsize = rectString.size;
    CGRect frame = label.frame;
    frame.size = labelsize;
    [label setFrame:frame];
}

#pragma mark -- animation

//if u want to add badge animation type, follow steps bellow:
//1. go to definition of WBadgeAnimType and add new type
//2. go to category of CAAnimation+WAnimation to add new animation interface
//3. call that new interface here
- (void)beginAnimation
{
    switch(self.aniType) {
        case WBadgeAnimTypeBreathe:
            [self.badge.layer addAnimation:[CAAnimation opacityForever_Animation:1.4]
                                    forKey:kBadgeBreatheAniKey];
            break;
        case WBadgeAnimTypeShake:
            [self.badge.layer addAnimation:[CAAnimation shake_AnimationRepeatTimes:CGFLOAT_MAX
                                                                          durTimes:1
                                                                            forObj:self.badge.layer]
                                    forKey:kBadgeShakeAniKey];
            break;
        case WBadgeAnimTypeScale:
            [self.badge.layer addAnimation:[CAAnimation scaleFrom:1.4
                                                          toScale:0.6
                                                         durTimes:1
                                                              rep:MAXFLOAT]
                                    forKey:kBadgeScaleAniKey];
            break;
        case WBadgeAnimTypeBounce:
            [self.badge.layer addAnimation:[CAAnimation bounce_AnimationRepeatTimes:CGFLOAT_MAX
                                                                          durTimes:1
                                                                            forObj:self.badge.layer]
                                    forKey:kBadgeBounceAniKey];
            break;
        case WBadgeAnimTypeNone:
        default:
            break;
    }
}


- (void)removeAnimation
{
    if (self.badge) {
        [self.badge.layer removeAllAnimations];
    }
}


#pragma mark -- setter/getter
- (BadgeLabel *)badge
{
    return objc_getAssociatedObject(self, &badgeLabelKey);
}

- (void)setBadge:(BadgeLabel *)label
{
    objc_setAssociatedObject(self, &badgeLabelKey, label, OBJC_ASSOCIATION_RETAIN);
}

- (UIColor *)badgeBgColor
{
    return objc_getAssociatedObject(self, &badgeBgColorKey);
}

- (void)setBadgeBgColor:(UIColor *)badgeBgColor
{
    objc_setAssociatedObject(self, &badgeBgColorKey, badgeBgColor, OBJC_ASSOCIATION_RETAIN);
    if (self.badge) {
        self.badge.backgroundColor = badgeBgColor;
    }
}

- (UIColor *)badgeTextColor
{
    return objc_getAssociatedObject(self, &badgeTextColorKey);
}

- (void)setBadgeTextColor:(UIColor *)badgeTextColor
{
    objc_setAssociatedObject(self, &badgeTextColorKey, badgeTextColor, OBJC_ASSOCIATION_RETAIN);
    if (self.badge) {
        self.badge.textColor = badgeTextColor;
    }
}

- (WBadgeAnimType)aniType
{
    id obj = objc_getAssociatedObject(self, &badgeAniTypeKey);
    if(obj != nil && [obj isKindOfClass:[NSNumber class]])
    {
        return [obj integerValue];
    }
    else
        return WBadgeAnimTypeNone;
}

- (void)setAniType:(WBadgeAnimType)aniType
{
    NSNumber *numObj = @(aniType);
    objc_setAssociatedObject(self, &badgeAniTypeKey, numObj, OBJC_ASSOCIATION_RETAIN);
    if (self.badge) {
        [self removeAnimation];
        [self beginAnimation];
    }
}

- (CGRect)badgeFrame
{
    id obj = objc_getAssociatedObject(self, &badgeFrameKey);
    if (obj != nil && [obj isKindOfClass:[NSDictionary class]] && [obj count] == 4) {
        CGFloat x = [obj[@"x"] floatValue];
        CGFloat y = [obj[@"y"] floatValue];
        CGFloat width = [obj[@"width"] floatValue];
        CGFloat height = [obj[@"height"] floatValue];
        return  CGRectMake(x, y, width, height);
    } else
        return CGRectZero;
}

- (void)setBadgeFrame:(CGRect)badgeFrame
{
    NSDictionary *frameInfo = @{@"x" : @(badgeFrame.origin.x), @"y" : @(badgeFrame.origin.y),
                                @"width" : @(badgeFrame.size.width), @"height" : @(badgeFrame.size.height)};
    objc_setAssociatedObject(self, &badgeFrameKey, frameInfo, OBJC_ASSOCIATION_RETAIN);
    
    if (self.badge.tag == WBadgeStyleRectangle) {
        UIView *bgView = (UIView *)[self viewWithTag:(WBadgeStyleRectangle+111)];
        if (bgView) {
            bgView.frame = badgeFrame;
        }
    }
    if (self.badge) {
        self.badge.frame = badgeFrame;
    }
}

- (CGPoint)badgeCenterOffset
{
    id obj = objc_getAssociatedObject(self, &badgeCenterOffsetKey);
    if (obj != nil && [obj isKindOfClass:[NSDictionary class]] && [obj count] == 2) {
        CGFloat x = [obj[@"x"] floatValue];
        CGFloat y = [obj[@"y"] floatValue];
        return CGPointMake(x, y);
    } else
        return CGPointZero;
}

- (void)setBadgeCenterOffset:(CGPoint)badgeCenterOff
{
    if (self.badge.tag == WBadgeStyleRectangle) {
        UIView *bgView = (UIView *)[self viewWithTag:(WBadgeStyleRectangle+111)];
        if (bgView) {
            bgView.center = CGPointMake(CGRectGetWidth(self.frame) + 2 + badgeCenterOff.x, badgeCenterOff.y);
        }
        return;
    }
    NSDictionary *cenerInfo = @{@"x" : @(badgeCenterOff.x), @"y" : @(badgeCenterOff.y)};
    objc_setAssociatedObject(self, &badgeCenterOffsetKey, cenerInfo, OBJC_ASSOCIATION_RETAIN);
    if (self.badge) {
        self.badge.center = CGPointMake(CGRectGetWidth(self.frame) + 2 + badgeCenterOff.x, badgeCenterOff.y);
    }
}

struct CornerRadii {
    CGFloat topLeft ;
    CGFloat topRight;
    CGFloat bottomLeft;
    CGFloat bottomRight;
};

///切圆角函数绘制线条
- (UIBezierPath *)createPathWithRoundedRect:(CGRect)bounds cornerRadii:(struct CornerRadii)cornerRadii{
    UIBezierPath *path = [UIBezierPath bezierPath];
    CGFloat height = bounds.size.height;
    CGFloat width = bounds.size.width;

    [path moveToPoint:CGPointMake(cornerRadii.topLeft, 0)];
    [path addQuadCurveToPoint:CGPointMake(0, cornerRadii.topLeft) controlPoint:CGPointZero];

    [path addLineToPoint:CGPointMake(0, height - cornerRadii.bottomLeft)];
    [path addQuadCurveToPoint:CGPointMake(cornerRadii.bottomLeft, height) controlPoint:CGPointMake(0, height)];

    [path addLineToPoint:CGPointMake(width - cornerRadii.bottomRight, height)];
    [path addQuadCurveToPoint:CGPointMake(width, height - cornerRadii.bottomRight) controlPoint:CGPointMake(width, height)];

    [path addLineToPoint:CGPointMake(width, cornerRadii.topRight)];
    [path addQuadCurveToPoint:CGPointMake(width - cornerRadii.topRight, 0) controlPoint:CGPointMake(width, 0)];
    [path closePath];
    [path addClip];
    return path;
}
@end

@implementation BadgeLabel

- (void)drawTextInRect:(CGRect)rect {
    CGRect r = rect;
    if ([self.text isEqualToString:@"..."]) {//解决三个点渲染偏下问题
        r.origin.y = -2.8;
    }
    [super drawTextInRect:r];
}

@end
